//	---------------------------------------------------------------------------
//
//	@file		TwEventX11.c
//	@brief		Helper:
//				translate and forward mouse and keyboard events
//				from X11 to AntTweakBar
//
//	@contrib	Greg Popovitch
//	@license	This file is part of the AntTweakBar library.
//				For conditions of distribution and use, see License.txt
//
//	---------------------------------------------------------------------------

#if !defined TW_NO_X11_EVENTS

#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xutil.h>
#include <AntTweakBar.h>

static int s_KMod = 0;
const int buff_sz = 80;

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
/*
static int _XKeyRelease(XEvent *event)
{
	KeySym keysym;
	char buffer[buff_sz];

	XLookupString((XKeyEvent *)event, buffer, buff_sz, &keysym, 0);

	switch (keysym)
	{
	case XK_Control_L:
	case XK_Control_R: s_KMod  &= ~TW_KMOD_CTRL;  break;

	case XK_Shift_L:
	case XK_Shift_R:   s_KMod &= ~TW_KMOD_SHIFT;  break;

	case XK_Alt_L:
	case XK_Alt_R:	   s_KMod &= ~TW_KMOD_ALT;	  break;
	}
	return 0;
}
*/

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
static int _XKeyPress(XEvent *event)
{
	int modifiers = 0;	// modifiers sent to AntTweakBar
	int k = 0;			// key sent to AntTweakBar
	KeySym keysym;
	char buffer[buff_sz];

	int num_char = XLookupString((XKeyEvent *)event, buffer, buff_sz, &keysym, 0);

	if (event->xkey.state & ControlMask)
		modifiers |= TW_KMOD_CTRL;
	if (event->xkey.state & ShiftMask)
		modifiers |= TW_KMOD_SHIFT;
	if (event->xkey.state & Mod1Mask)
		modifiers |= TW_KMOD_ALT;

	switch (keysym)
	{
	case XK_Control_L:
	case XK_Control_R: s_KMod |= TW_KMOD_CTRL;	break;

	case XK_Shift_L:
	case XK_Shift_R:   s_KMod |= TW_KMOD_SHIFT; break;

	case XK_Alt_L:
	case XK_Alt_R:	   s_KMod |= TW_KMOD_ALT;	break;

	case XK_Escape:    k = TW_KEY_ESCAPE;	 break;
	case XK_Help:	   k = TW_KEY_F1;		 break;
	case XK_F1:		   k = TW_KEY_F1;		 break;
	case XK_F2:		   k = TW_KEY_F2;		 break;
	case XK_F3:		   k = TW_KEY_F3;		 break;
	case XK_F4:		   k = TW_KEY_F4;		 break;
	case XK_F5:		   k = TW_KEY_F5;		 break;
	case XK_F6:		   k = TW_KEY_F6;		 break;
	case XK_F7:		   k = TW_KEY_F7;		 break;
	case XK_F8:		   k = TW_KEY_F8;		 break;
	case XK_F9:		   k = TW_KEY_F9;		 break;
	case XK_F10:	   k = TW_KEY_F10;		 break;
	case XK_F11:	   k = TW_KEY_F11;		 break;
	case XK_F12:	   k = TW_KEY_F12;		 break;
	case XK_Up:		   k = TW_KEY_UP;		 break;
	case XK_Down:	   k = TW_KEY_DOWN;		 break;
	case XK_Right:	   k = TW_KEY_RIGHT;	 break;
	case XK_Left:	   k = TW_KEY_LEFT;		 break;
	case XK_Return:    k = TW_KEY_RETURN;	 break;
	case XK_Insert:    k = TW_KEY_INSERT;	 break;
	case XK_Delete:    k = TW_KEY_DELETE;	 break;
	case XK_BackSpace: k = TW_KEY_BACKSPACE; break;
	case XK_Home:	   k = TW_KEY_HOME;		 break;
	case XK_Tab:	   k = TW_KEY_TAB;		 break;
	case XK_End:	   k = TW_KEY_END;		 break;

#ifdef XK_Enter
	case XK_Enter:	   k = TW_KEY_RETURN;	 break;
#endif

#ifdef XK_KP_Home
	case XK_KP_Home:   k = TW_KEY_HOME;		 break;
	case XK_KP_End:    k = TW_KEY_END;		 break;
	case XK_KP_Delete: k = TW_KEY_DELETE;	 break;
#endif

#ifdef XK_KP_Up
	case XK_KP_Up:	   k = TW_KEY_UP;		 break;
	case XK_KP_Down:   k = TW_KEY_DOWN;		 break;
	case XK_KP_Right:  k = TW_KEY_RIGHT;	 break;
	case XK_KP_Left:   k = TW_KEY_LEFT;		 break;
#endif

#ifdef XK_KP_Page_Up
	case XK_KP_Page_Up:   k = TW_KEY_PAGE_UP;	 break;
	case XK_KP_Page_Down: k = TW_KEY_PAGE_DOWN;  break;
#endif

#ifdef XK_KP_Tab
	case XK_KP_Tab:    k = TW_KEY_TAB;		 break;
#endif

	default:
		if (0)
		{
			// should we do that, or rely on the buffer (see code below)
			if (keysym > 12 && keysym < 127)
				k = keysym;
		}
		break;
	}

	if (k == 0 && num_char)
	{
		int i, handled = 0;
		for (i=0; i<num_char; ++i)
			if (TwKeyPressed(buffer[i], modifiers))
				handled = 1;
		return handled;
	}

	// if we have a valid key, send to AntTweakBar
	// -------------------------------------------
	return (k > 0) ? TwKeyPressed(k, modifiers) : 0;
}

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
static int _XButtonEvent(XEvent *event)
{
	TwMouseAction action = (event->type == ButtonPress) ? TW_MOUSE_PRESSED : TW_MOUSE_RELEASED;
	XButtonEvent *xbe = (XButtonEvent *)event;
	return TwMouseButton(action, xbe->button);
}

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
static int _XConfigureEvent(XEvent *event)
{
	XConfigureEvent *xce = (XConfigureEvent *)event;
	TwWindowSize(xce->width, xce->height);
	return 0;
}

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
static int _XMotionEvent(XEvent *event)
{
	XMotionEvent *xme = (XMotionEvent *)event;
	return TwMouseMotion(xme->x, xme->y);
}

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
TW_API int TW_CDECL_CALL TwEventX11(void *xevent)
{
	XEvent *event = (XEvent *)xevent;

	switch (event->type)
	{
	case KeyPress:
		return _XKeyPress(xevent);

	case KeyRelease:
		return 0; // _XKeyRelease(xevent);

	case ButtonPress:
	case ButtonRelease:
		return _XButtonEvent(xevent);

	case MotionNotify:
		return _XMotionEvent(xevent);

	case ConfigureNotify:
		return _XConfigureEvent(xevent);

	default:
		break;
	}
	return 0;
}

#endif // !defined TW_NO_X11_EVENTS

